package org.apache.sad.core.framework.spring;

import java.io.File;
import java.io.FileNotFoundException;
import java.net.URL;

import org.apache.log4j.LogManager;
import org.apache.log4j.xml.DOMConfigurator;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.ResourceUtils;
import org.springframework.util.SystemPropertyUtils;

import org.apache.sad.core.framework.logging.log4j.PropertyConfigurator;

public class Log4jConfigurer implements InitializingBean, DisposableBean {
	public static final long DEFAULT_REFRESH = 60000;

	private String location;

	private long refreshInterval = DEFAULT_REFRESH;

	public String getLocation() {
		return location;
	}

	public void setLocation(String location) {
		this.location = location;
	}

	public long getRefreshInterval() {
		return refreshInterval;
	}

	public void setRefreshInterval(long refreshInterval) {
		this.refreshInterval = refreshInterval;
	}

	public void afterPropertiesSet() throws Exception {
		initLogging(getLocation(), getRefreshInterval());
	}

	public static void initLogging(String configLocation) throws FileNotFoundException {
		initLogging(configLocation, DEFAULT_REFRESH);
	}

	public static void initLogging(String configLocation, long refreshInterval) throws FileNotFoundException {
		try {
			initializeLogging(configLocation, refreshInterval);
		} catch (Exception e) {
			System.out.println("Unable to initialize logging using configured location due to: " + e.getMessage() + ". Try to locate configuration in the classpath.");
			initializeLogging(getClasspathLocation(configLocation), 0);
		}
	}

	private static void initializeLogging(String configLocation, long refreshInterval) throws FileNotFoundException {
		boolean isFileResource = configLocation.startsWith("file:");
		if ( isFileResource ) {
			String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(configLocation);
			File file = ResourceUtils.getFile(resolvedLocation);
			if ( !file.exists() ) {
				throw new FileNotFoundException("" + file.getAbsolutePath() + " doesn't exist");
			}
		}
		if ( refreshInterval > 0 && isFileResource ) {
			doInitLogging(configLocation, refreshInterval);
		} else {
			doInitLogging(configLocation);
		}
		System.out.println("Initialized logging with configuration: " + configLocation);
	}

	private static String getClasspathLocation(String configLocation) {
		int lastFileSeparatorIndex = -1;
		for ( String separator : FILE_SEPARATORS ) {
			lastFileSeparatorIndex = configLocation.lastIndexOf(separator);
			if ( lastFileSeparatorIndex > 0 ) {
				break;
			}
		}
		return "classpath:" + configLocation.substring(lastFileSeparatorIndex + 1);
	}

	private final static String[] FILE_SEPARATORS = new String[] {"/", "\\", ":"};

	public void destroy() throws Exception {
		shutdownLogging();
	}
	
	public static void doInitLogging(String location) throws FileNotFoundException {
		String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
		URL url = ResourceUtils.getURL(resolvedLocation);
		if (resolvedLocation.toLowerCase().endsWith(".xml"))
			DOMConfigurator.configure(url);
		else
			PropertyConfigurator.configure(url);
	}

	public static void doInitLogging(String location, long refreshInterval) throws FileNotFoundException {
		String resolvedLocation = SystemPropertyUtils.resolvePlaceholders(location);
		File file = ResourceUtils.getFile(resolvedLocation);
		if (!(file.exists()))
			throw new FileNotFoundException("Log4J config file [" + resolvedLocation + "] not found");

		if (resolvedLocation.toLowerCase().endsWith(".xml"))
			DOMConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
		else
			PropertyConfigurator.configureAndWatch(file.getAbsolutePath(), refreshInterval);
	}

	public static void shutdownLogging() {
		LogManager.shutdown();
	}	
}
